package com.javabi.htmlbuilder;

/**
 * An HTML Color.
 */
public class HTMLColor {

	/** Single digit. */
	private static final int SINGLE = 16;
	/** Single digit. */
	private static final int PERCENT = 100;
	/** Double digit. */
	private static final int DOUBLE = 256;
	/** The hex characters. */
	private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

	/** The color black. */
	public static final HTMLColor BLACK = new HTMLColor(0, 0, 0);
	/** The color white. */
	public static final HTMLColor WHITE = new HTMLColor(255, 255, 255);

	/**
	 * Parse an HTML color from the given string.
	 * @param color the color string.
	 * @return the color.
	 */
	public static final HTMLColor parseHTMLColor(String color) {
		if (color.length() == 7) {
			if (color.charAt(0) != '#') {
				throw new IllegalArgumentException("badly formatted color: '" + color + "'");
			}
			color = color.substring(1, 7);
		} else if (color.length() != 6) {
			throw new IllegalArgumentException("badly formatted color: '" + color + "'");
		}
		int red = Integer.parseInt(color.substring(0, 2), 16);
		int green = Integer.parseInt(color.substring(2, 4), 16);
		int blue = Integer.parseInt(color.substring(4, 6), 16);
		return new HTMLColor(red, green, blue);
	}

	/**
	 * Append a hex representation of the given value to the builder.
	 * @param builder the builder.
	 * @param hex the hex.
	 * @param single true for single digit (16), false for double digit (256)
	 * @return the builder.
	 */
	public static final StringBuilder appendHex(StringBuilder builder, int hex, boolean single) {
		if (hex < 0 || (single ? hex >= SINGLE : hex >= DOUBLE)) {
			throw new IllegalArgumentException("hex=" + hex);
		}
		builder.append(HEX[hex / SINGLE]);
		builder.append(HEX[hex % SINGLE]);
		return builder;
	}

	/**
	 * Append a hex representation of the given color to the builder.
	 * @param builder the builder.
	 * @param red the red component.
	 * @param green the green component
	 * @param blue the blue component
	 * @param single true for single digit (16), false for double digit (DOUBLE)
	 * @return the builder.
	 */
	public static final StringBuilder appendHex(StringBuilder builder, int red, int green, int blue, boolean single) {
		if (red < 0 || (single ? red >= SINGLE : red >= DOUBLE)) {
			throw new IllegalArgumentException("red=" + red);
		}
		if (green < 0 || (single ? green >= SINGLE : green >= DOUBLE)) {
			throw new IllegalArgumentException("green=" + green);
		}
		if (blue < 0 || (single ? blue >= SINGLE : blue >= DOUBLE)) {
			throw new IllegalArgumentException("blue=" + blue);
		}
		builder.append('#');
		builder.append(HEX[red / SINGLE]);
		builder.append(HEX[red % SINGLE]);
		builder.append(HEX[green / SINGLE]);
		builder.append(HEX[green % SINGLE]);
		builder.append(HEX[blue / SINGLE]);
		builder.append(HEX[blue % SINGLE]);
		return builder;
	}

	/**
	 * Append an RGB representation of the given color to the builder.
	 * @param builder the builder.
	 * @param red the red component.
	 * @param green the green component
	 * @param blue the blue component
	 * @param percent true for percentages.
	 * @return the builder.
	 */
	public static final StringBuilder appendRGB(StringBuilder builder, int red, int green, int blue, boolean percent) {
		if (red < 0 || (percent ? red > PERCENT : red >= DOUBLE)) {
			throw new IllegalArgumentException("red=" + red);
		}
		if (green < 0 || (percent ? green > PERCENT : green >= DOUBLE)) {
			throw new IllegalArgumentException("green=" + green);
		}
		if (blue < 0 || (percent ? blue > PERCENT : blue >= DOUBLE)) {
			throw new IllegalArgumentException("blue=" + blue);
		}
		builder.append("rgb(");
		builder.append(red);
		if (percent) {
			builder.append('%');
			builder.append(',');
			builder.append(green);
			builder.append('%');
			builder.append(',');
			builder.append(blue);
			builder.append('%');
		} else {
			builder.append(',');
			builder.append(green);
			builder.append(',');
			builder.append(blue);
		}
		builder.append(')');
		return builder;
	}

	/** The red. */
	private final short red;
	/** The green. */
	private final short green;
	/** The blue. */
	private final short blue;

	/**
	 * Creates a new color.
	 * @param red the red.
	 * @param green the green.
	 * @param blue the blue.
	 */
	public HTMLColor(int red, int green, int blue) {
		if (red < 0 || red >= DOUBLE) {
			throw new IllegalArgumentException("red=" + red);
		}
		if (green < 0 || green >= DOUBLE) {
			throw new IllegalArgumentException("green=" + green);
		}
		if (blue < 0 || blue >= DOUBLE) {
			throw new IllegalArgumentException("blue=" + blue);
		}
		this.red = (short) red;
		this.green = (short) green;
		this.blue = (short) blue;
	}

	/**
	 * Creates a new color.
	 * @param color the color.
	 */
	public HTMLColor(HTMLColor color) {
		this.red = color.red;
		this.green = color.green;
		this.blue = color.blue;
	}

	/**
	 * Returns the red.
	 * @return the red.
	 */
	public int getRed() {
		return red;
	}

	/**
	 * Returns the green.
	 * @return the green.
	 */
	public int getGreen() {
		return green;
	}

	/**
	 * Returns the blue.
	 * @return the blue.
	 */
	public int getBlue() {
		return blue;
	}

	/**
	 * Append this color to the given string builder.
	 * @param builder the builder.
	 * @return the builder.
	 */
	public StringBuilder appendTo(StringBuilder builder) {
		appendHex(builder, getRed(), getGreen(), getBlue(), false).toString();
		return builder;
	}

	@Override
	public String toString() {
		return appendTo(new StringBuilder()).toString();
	}

}
